--[[
Author: wangxiaoyan
Date: 2020-09-27 15:05:15
LastEditTime: 2020-10-29 11:10:29
FilePath: \Lua\Common\Class.lua

提供类机制
--]]
--region 方法重载
local function create()
    local arg_table = {}
    local function dispatcher(...)
        local tbl = arg_table
        local n = select("#",...)
        local last_match
        for i = 1,n do
            local t = type(select(i,...))
            local n = tbl[t]
            last_match = tbl["..."] or last_match
            if not n then
                return last_match(...)
            end
            tbl = n
        end
        return (tbl["__end"] or tbl["..."])(...)
    end
    local function register(desc,func)
        local tbl = arg_table
        for _,v in ipairs(desc) do
            if v == "..." then
                assert(not tbl["..."])
                tbl["..."] = func
                return
            end
            local n = tbl[v]
            if not n then
                n = {}
                tbl[v] = n
            end
            tbl = n
        end
        tbl["__end"] = func
    end
    return dispatcher,register,arg_table
end
local function register(t,desc,name)
    local func = desc[1]
    assert(type(func) == "function")
    table.remove(desc,1)
    local func_table
    local ovName = string.gsub(name,"__overload","")
    local all = rawget(t,"__overloadAll")
    if not all then
        all = {}
        rawset(t,"__overloadAll",all)
    end
    if all[name] then
        func_table = all[name]
    else
        func_table = {}
        all[name] = func_table
    end
    local ovFunc = rawget(t,ovName)
    if  ovFunc then
        assert(func_table[name])
    else
        t[ovName],func_table[name] = create()
    end
    func_table[name](desc,func)
end
local __superOverloadClass = {
    __index = function(t,k)
        if string.find(k,"__overload") ~= nil then
            local function reg(desc)
                register(t,desc,k)
            end
            t[k] = reg
            return reg
        end
        return rawget(t,k)
    end
}
--endregion 方法重载
function clone(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for key, value in pairs(object) do
            new_table[_copy(key)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

--Create an class.
function Class(classname, super)
    local superType = type(super)
    local cls

    if superType ~= "function" and superType ~= "table" then
        superType = nil
        super = nil
    end

    if superType == "function" or (super and super.__ctype == 1) then
        -- inherited from native C++ Object
        cls = {}

        if superType == "table" then
            -- copy fields from super
            for k,v in pairs(super) do cls[k] = v end
            cls.__create = super.__create
            cls.super    = super
        else
            cls.__create = super
        end

        cls.ctor    = function() end
        cls.__cname = classname
        cls.__ctype = 1

        function cls.New(...)
            local instance = cls.__create(...)
            -- copy fields from class to native object
            for k,v in pairs(cls) do instance[k] = v end
            instance.class = cls
            if instance.ctor then
                instance:ctor(...)
            end
            return instance
        end

    else
        -- inherited from Lua Object
        if super then
            cls = setmetatable(clone(super),__superOverloadClass)
            cls.super = super
        else
            cls = setmetatable({},__superOverloadClass)
        end

        cls.__cname = classname
        cls.__ctype = 2 -- lua
        cls.__index = cls

        function cls.New(...)
            local instance = setmetatable({}, cls)
            instance.class = cls
            if instance.ctor then
                instance:ctor(...)
            end
            return instance
        end
    end

    return cls
end

function Interface(class,interface)
    for key, value in pairs(interface) do
        if not class[key] then
            class[key] = value
        end
    end
    return class
end
function addOverload(table,name,func,...)
    table["__overload"..name]{func,...}
end